package spark.math;

public class Vector2 {
	public static final int SIZE = Float.SIZE * 2;

	public float x;
	public float y;

	public Vector2() {
	}

	public Vector2(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public Vector2(final Vector2 source) {
		this.x = source.x;
		this.y = source.y;
	}

	public static float dot(final Vector2 aLeft, final Vector2 aRight) {
		return
				aLeft.x * aRight.x +
				aLeft.y * aRight.y;
	}

	public static Vector2 normalize(final Vector2 aVector) {
		Vector2 normalizedVector = new Vector2(aVector);
		normalizedVector.normalize();
		return normalizedVector;
	}

	public void normalize() {
		float length = this.length();

		if(length > 0) {
			x /= length;
			y /= length;
		}
	}

	public static float length(final Vector2 aVector) {
		return (float) Math.sqrt(
				aVector.x * aVector.x +
				aVector.y * aVector.y);
	}

	public float length() {
		return length(this);
	}

	public static float lengthWithoutSquareRoot(final Vector2 aVector) {
		return
				aVector.x * aVector.x +
				aVector.y * aVector.y;
	}

	public float lengthWithoutSquareRoot() {
		return lengthWithoutSquareRoot(this);
	}

	public static Vector2 lerp(final Vector2 aLeft, final Vector2 aRight, float aInterpolater) {
		return Vector2.add(Vector2.multiply(aLeft, 1.0f - aInterpolater), Vector2.multiply(aRight, aInterpolater));
	}

	public static Vector2 add(final Vector2 left, final Vector2 right) {
		return new Vector2(left.x + right.x, left.y + right.y);
	}

	public void add(final Vector2 vector) {
		this.x += vector.x;
		this.y += vector.y;
	}

	public static Vector2 substract(final Vector2 left, final Vector2 right) {
		return new Vector2(left.x - right.x, left.y - right.y);
	}

	public void substract(final Vector2 vector) {
		this.x -= vector.x;
		this.y -= vector.y;
	}

	public static Vector2 multiply(final Vector2 vector, final float scalar) {
		return new Vector2(vector.x * scalar, vector.y * scalar);
	}

	public void multiply(final float scalar) {
		this.x *= scalar;
		this.y *= scalar;
	}

	public static Vector2 divide(final Vector2 vector, final float scalar) {
		return new Vector2(vector.x / scalar, vector.y / scalar);
	}

	public void divide(final float scalar) {
		this.x /= scalar;
		this.y /= scalar;
	}

	public static Vector2 rotate(final Vector2 vector, final float angle) {
		return new Vector2(vector.x * Geometry.cos(angle) - vector.y * Geometry.sin(angle),
		                   vector.x * Geometry.sin(angle) + vector.y * Geometry.cos(angle));
	}

	public void rotate(final float angle) {
		this.x = this.x * Geometry.cos(angle) - this.y * Geometry.sin(angle);
		this.y = this.x * Geometry.sin(angle) + this.y * Geometry.cos(angle);
	}

	public static void copy(Vector2 source, Vector2 target) {
		target.x = source.x;
		target.y = source.y;
	}

	public void copy(Vector2 vector) {
		this.x = vector.x;
		this.y = vector.y;
	}

	public static float angle(Vector2 reference, Vector2 vector) {
		return 2 * Geometry.atan2(vector.y - reference.y, vector.x - reference.x);
	}

	public float angle(Vector2 vector) {
		return 2 * Geometry.atan2(vector.y - y, vector.x - x);
	}

	public boolean isZero() {
		return x == 0 && y == 0;
	}

	@Override
	public String toString() {
		return "X(" + x + ") Y(" + y + ")";
	}

	@Override
	public boolean equals(Object o) {
		if(this == o) return true;
		if(o == null || getClass() != o.getClass()) return false;

		Vector2 vector2 = (Vector2) o;

		if(Float.compare(vector2.x, x) != 0) return false;
		if(Float.compare(vector2.y, y) != 0) return false;

		return true;
	}

	public void zero() {
		x = y = 0.0f;
	}
}
